#pragma once
#include "../mqcommon/helper.hpp"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <vector>
#include <mutex>
#include <sstream>
namespace wzf
{
    //交换机类
    struct Exchange
    {
        using ptr = std::shared_ptr<Exchange>; //用智能指针来管理交换机对象
        std::string name;           //交换机名字
        ExchangeType type;          //交换机类型
        DeliveryMode durable;       //是否持久化存储
        bool auto_delete;          //是否自动删除
        std::unordered_map<std::string, std::string> args;  //其他参数
        Exchange(){}
        Exchange(const std::string& ename, ExchangeType etype, DeliveryMode edurable, bool eauto_delete, 
            const std::unordered_map<std::string, std::string>& eargs)
            : name(ename), type(etype), durable(edurable), auto_delete(eauto_delete), args(eargs)
        {} //args(eargs)后序处理，因为proto里没有unordered_map 只有map

        void SetArgs(const std::string& str_args) //数据库中 key=value，函数目的，解析数据库中的字符串
        {
            std::vector<std::string> sub_args;
            StrHelper::split(str_args, "&", sub_args);
            for(auto& str : sub_args)
            {
                size_t pos = str.find("=");
                std::string key = str.substr(0, pos);
                std::string val = str.substr(pos + 1);
                args.insert({key, val});
            }
        }
        std::string GetArgs() //将args内容序列化后返回一个字符串，便于存储到数据库中
        {
            std::string result;
            for(auto cur = args.begin(); cur != args.end(); ++cur)
            {
                result += cur->first + "=" + cur->second + "&";
            }
            return result;
        }
    };

    //交换机数据持久化存储管理类 ----- 在sqlite中的数据 --- 内部 --- 磁盘的交换机数据管理
    class ExchangeMapper
    {
    public:
        ExchangeMapper(const std::string& dbfile)
            :_sql_helper(dbfile)    
        {
            std::string path = FileHelper::getParentDirectory(dbfile); 
            FileHelper::createDirectory(path);          //创建父目录
            assert(_sql_helper.open());
            CreateTable();
        }
        void CreateTable()
        {
            #define CREATE_TABLE "create table if not exists exchange_table(\
                name varchar(32) primary key, \
                type int, \
                durable int, \
                auto_delete int, \
                args varchar(128));"
            bool ret = _sql_helper.exec(CREATE_TABLE, nullptr, nullptr);
            if(ret == false)
            {
                ELOG("交换机的数据库表创建失败");
                abort();
            }
        }
        void RemoveTable()
        {
            #define DROP_TABLE "drop table if exists exchange_table;"
            bool ret = _sql_helper.exec(DROP_TABLE, nullptr, nullptr);
            if(ret == false)
            {
                ELOG("交换机的数据库表删除失败");
                abort();
            }
        }
        bool Insert(Exchange::ptr& ptr)
        {
            std::stringstream ss;
            ss << "insert into exchange_table values(";
            ss << "'" << ptr->name << "',";
            ss << ptr->type << ",";
            ss << ptr->durable << ",";
            ss << ptr->auto_delete << ",";
            ss << "'" << ptr->GetArgs() << "');";
            // DLOG("生成的 SQL 语句: %s", ss.str().c_str());
            return _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        void Remove(const std::string& name)
        {
            std::stringstream ss;
            ss << "delete from exchange_table where name=";
            ss << "'" << name << "';";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }

        //恢复历史数据
        using ExchangeMap = std::unordered_map<std::string, Exchange::ptr>;
        ExchangeMap Recovery() //name和交换机对象的映射
        {
            ExchangeMap result;
            std::string sql = "select * from exchange_table";
            _sql_helper.exec(sql, SelectCallBack, &result);
            return result;
        }
    private:
        static int SelectCallBack(void* arg, int col, char** row, char** fields)
        {
            ExchangeMap* result = static_cast<ExchangeMap*>(arg);
            auto ptr = std::make_shared<Exchange>();

            ptr->name = row[0];
            ptr->type = static_cast<ExchangeType>(std::stoi(row[1]));
            ptr->durable = static_cast<DeliveryMode>(std::stoi(row[2]));
            ptr->auto_delete = static_cast<bool>(std::stoi(row[3]));
            if(row[4]) ptr->SetArgs(row[4]);
            result->insert({ptr->name, ptr});

            return 0;
        }
    private:
        SqliteHelper _sql_helper;
    };
    
    //交换机数据内存管理类 --- 对外的
    class ExchangeManager
    {
    public:
        // using ptr = std::shared_ptr<ExchangeManager>;
        ExchangeManager(const std::string& dbfile)
            : _mapper(dbfile)
        {
            _exchanges = _mapper.Recovery();
        }
        //声明交换机
        void DeclareExchange(const std::string& name, ExchangeType type, DeliveryMode durable, bool auto_delete, 
            const std::unordered_map<std::string, std::string>& args)
        {
            std::unique_lock<std::mutex> lock(_mutex); 
            auto ptr = std::make_shared<Exchange>(name, type, durable, auto_delete, args);
            if(_exchanges.count(name) == false)
            {
                _exchanges.insert({name, ptr});
                if(ptr->durable == DeliveryMode::DURABLE)
                {
                    _mapper.Insert(ptr);
                    DLOG("_mapper.Insert(ptr)");
                } 
            }
        }
        //删除指定交换机
        void DeleteExchange(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex); 
            auto it = _exchanges.find(name);
            if(it != _exchanges.end())
            {
                _exchanges.erase(name);
                if(it->second->durable == DURABLE) _mapper.Remove(name);
            }
        }
        Exchange::ptr SelectExchange(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex); 
            auto it = _exchanges.find(name);
            if(it != _exchanges.end())
            {
                return it->second;
            }
            return nullptr;
        }
        //交换机是否存在
        bool Exists(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex); 
            if(_exchanges.count(name))
            {
                return true;
            }
            return false;
        }
        //删除所有交换机
        void Clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);  
            _mapper.RemoveTable();     //
            _exchanges.clear();
        }       

        int Size()
        {
            std::unique_lock<std::mutex> lock(_mutex);  
            return _exchanges.size();
        }
    private:
        std::mutex _mutex;
        ExchangeMapper _mapper;
        std::unordered_map<std::string, Exchange::ptr> _exchanges; //共享资源
    };
};


